﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using AsterNET.Extensions.FastAGI.Helpers;
using AsterNET.FastAGI;
using AsterNET.FastAGI.Command;

namespace AsterNET.Extensions.FastAGI.AGIScript
{
    public abstract class AGIScript : AsterNET.FastAGI.AGIScript
    {
        /// <summary>
        /// </summary>
        /// <param name="channel">The currently executing AGI Channel</param>
        /// <param name="peer">
        ///     <para>Combination of Type/Identifier</para>
        ///     <para>
        ///         TYPE: specifies the channel type. It should be one of the registered channel types, such as "Zap", "SIP",
        ///         "IAX2", and so on.
        ///     </para>
        ///     <para>
        ///         IDENTIFIER: specifies the "phone number" to dial on that channel. The format of the "phone number" depends on
        ///         the channel, and may contain additonal parameters (e.g. a distinctive ring parameter) specific to the channel
        ///         module in question; the Dial command simply passes identifier to the channel module to process in whatever way
        ///         is appropriate. See the documentation for the individual channel modules to learn about the correct format for
        ///         specifying the identifier for the Dial command, and the options available to you when doing so. If you need a
        ///         .5 second pause while dialing a number you can insert a w in the appropriate place.
        ///     </para>
        /// </param>
        /// <param name="timeout">
        ///     <para>
        ///         The timeout parameter is optional. If not specified, the Dial command will wait indefinitely, exiting only
        ///         when the originating channel hangs up, or all the dialed channels return a busy or error condition. Otherwise
        ///         it specifies a maximum time, in seconds, that the Dial command is to wait for a channel to answer.
        ///     </para>
        /// </param>
        /// <param name="url">
        ///     <para>
        ///         The optional URL parameter will also be sent to the called party upon successful connection, if the channel
        ///         technology supports the sending of URLs in this way.
        ///     </para>
        ///     <para>Use NULL if not applicable</para>
        /// </param>
        /// <param name="options"></param>
        /// <returns>DialStatus</returns>
        public DialStatus Dial(
            string peer,
            int timeout,
            [Optional] string url,
            [Optional] params string[] options)
        {
            return DialHelper.Dial(Channel, peer, timeout, url, options);
        }

        /// <summary>
        /// Indicate busy condition and wait for hangup
        /// </summary>
        /// <param name="seconds">Optional timeout in seconds</param>
        /// <returns></returns>
        public void Busy(int seconds = 0)
        {
            Channel.SendCommand(BusyHelper.Busy(seconds));
        }

        /// <summary>
        /// Executes an Asterisk Gateway Interface compliant program on a channel. 
        /// AGI allows Asterisk to launch external programs written in any language to
        /// control a telephony channel, play audio, read DTMF digits, etc. by communicating 
        /// with the AGI protocol on stdin and stdout.
        /// </summary>
        /// <param name="agi"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public void AGI(string agi, params string[] arguments)
        {
            Channel.SendCommand(AGIHelper.AGI(agi, arguments));
        }

        /// <summary>
        /// Records The audio on the current channel to the specified file.
        /// </summary>
        /// <param name="filename">Filename to save the channel audio too, including the file extension (filename.ext)</param>
        /// <param name="command">Will be executed when the recording is over. Any strings matching ^{X} will be unescaped to ${X} and all variables will be evaluated at the time the application is called. Where <command> is a system (Linux shell) command, see Asterisk cmd System for example values.</param>
        /// <param name="options"></param>
        /// <returns></returns>
        public void MixMonitor(string filename, string command = null, params string[] options)
        {
            Channel.SendCommand(MixMonitorHelper.MixMonitor(filename, command, options));
        }

        /// <summary>
        /// This application originates an outbound call and connects it to a specified extension or application. 
        /// This application will block until the outgoing call fails or gets answered. At that point, 
        /// this application will exit with the status variable set and dialplan processing will continue.
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="tech">Channel technology and data for creating the outbound channel. For example, SIP/1234</param>
        /// <param name="type">This should be App or Exten, depending on whether the outbound channel should be connected to an application or extension.</param>
        /// <param name="arg1">If the type is App, then this is the application name. If the type is Exten, then this is the context that the channel will be sent to.</param>
        /// <param name="arg2">If the type is App, then this is the data passed as arguments to the application. If the type is Exten, then this is the extension that the channel will be sent to.</param>
        /// <param name="arg3">If the type is Exten, then this is the priority that the channel is sent to. If the type is App, then this parameter is ignored.</param>
        /// <returns>Status Enum: FAILED, SUCCESS, BUSY, CONGESTION, HANGUP, RINGING or UNKNOWN</returns>
        public OriginateStatus Originate(
            string tech,
            OriginateType type,
            string arg1,
            string arg2,
            string arg3)
        {
            return OriginateHelper.Originate(Channel, tech, type, arg1, arg2, arg3);
        }

        /// <summary>
        /// <para>Receive a FAX and save as a TIFF/F file.</para>
        /// <para>This application is provided by res_fax, which is a FAX technology agnostic module that utilizes FAX technology resource modules to complete a FAX transmission. Session arguments can be set by the FAXOPT function and to check results of the ReceiveFax() application.</para>
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public void ReceiveFax(string filename, params string[] options)
        {
            Channel.SendCommand(ReceiveFaxHelper.ReceiveFax(filename, options));
        }

        public void Ringing()
        {
            Channel.SendCommand(RingingHelper.Ringing());
        }

        /// <summary>
        /// Send an arbitrary event to the manager interface
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public void UserEvent(string eventName, params KeyValuePair<string, string>[] fields)
        {
            Channel.SendCommand(UserEventHelper.UserEvent(eventName, fields));
        }

        /// <summary>
        /// Send an arbitrary event to the manager interface
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        public void UserEvent(string eventName, string body)
        {
            Channel.SendCommand(UserEventHelper.UserEvent(eventName, body));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailbox"></param>
        /// <returns></returns>
        public VMStatus Voicemail(string mailbox)
        {
            return VoicemailHelper.Voicemail(Channel, mailbox);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailbox"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public VMStatus Voicemail(string mailbox, string context)
        {
            return VoicemailHelper.Voicemail(Channel, mailbox, context);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailbox"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        public VMStatus Voicemail(string mailbox, params string[] flags)
        {
            return VoicemailHelper.Voicemail(Channel, mailbox, null, flags);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mailbox"></param>
        /// <param name="context"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        public VMStatus Voicemail(string mailbox, string context, params string[] flags)
        {
            return VoicemailHelper.Voicemail(Channel, mailbox, context, flags);
        }

        /// <summary>
        /// Enters the main voicemail system for the checking of voicemail. The mailbox can be passed as the option, which will stop the voicemail system from prompting the user for the mailbox.
        /// </summary>
        /// <returns></returns>
        public void VoicemailMain()
        {
            VoicemailMainHelper.VoicemailMain();
        }

        /// <summary>
        /// Enters the main voicemail system for the checking of voicemail. The mailbox can be passed as the option, which will stop the voicemail system from prompting the user for the mailbox.
        /// </summary>
        /// <param name="mailbox"></param>
        /// <returns></returns>
        public void VoicemailMain(string mailbox)
        {
            VoicemailMainHelper.VoicemailMain(mailbox, null, new string[] { });
        }

        /// <summary>
        /// Enters the main voicemail system for the checking of voicemail. The mailbox can be passed as the option, which will stop the voicemail system from prompting the user for the mailbox.
        /// </summary>
        /// <param name="mailbox"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public void VoicemailMain(string mailbox, string context)
        {
            VoicemailMainHelper.VoicemailMain(mailbox, context, new string[] { });
        }

        /// <summary>
        /// Enters the main voicemail system for the checking of voicemail. The mailbox can be passed as the option, which will stop the voicemail system from prompting the user for the mailbox.
        /// </summary>
        /// <param name="mailbox"></param>
        /// <param name="context"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public void VoicemailMain(string mailbox, string context, params string[] options)
        {
            VoicemailMainHelper.VoicemailMain(mailbox, context, options);
        }

        /// <summary>
        /// Waits for specified time
        /// </summary>
        /// <param name="seconds">Number of seconds to wait</param>
        /// <returns></returns>
        public void Wait(int seconds)
        {
            Channel.SendCommand(WaitHelper.Wait(seconds));
        }
    }
}
